/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.nodes; import java.awt.Image; import java.awt.datatransfer.Transferable; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyEditor; import java.beans.FeatureDescriptor; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Enumeration; import java.util.Hashtable; import javax.swing.JPopupMenu; import javax.swing.event.EventListenerList; import org.openide.util.datatransfer.NewType; import org.openide.util.datatransfer.PasteType; import org.openide.util.HelpCtx; import org.openide.util.Mutex; import org.openide.util.NbBundle; import org.openide.util.actions.SystemAction; /** A <em>node</em> represents one element in a hierarchy of objects (beans). * It provides all methods that are needed for communication between * the IDE and the bean. * <P> * The node has three purposes: * <OL> * <LI>visually represent the object in the tree hierarchy (i.e. Explorer) * <LI>provide sets of properties for that object (i.e. Component Inspector, Property Sheet) * <LI>offer actions to perform on itself * </OL> * <P> * Frequently nodes are created to represent {@link org.openide.loaders.DataObject data objects}. * But they may also represent anything to be displayed to the user or manipulated programmatically, * even if they have no data directly stored behind them; for example, a control panel or debugger * breakpoint. * <P> * There are two listeners in this class: {@link PropertyChangeListener} * and {@link NodeListener} (which extends <code>PropertyChangeListener</code>). The first * is designed to listen on properties that can be returned from * {@link #getPropertySets}, the later for listening on changes in the * node itself (including the name, children, parent, set of properties, * icons, etc.). Be sure to distinguish between these two. * <P> * The node is cloneable. When a node is cloned, it is initialized * with an empty set of listeners and no parent. The display name and short description * are copied to the new node. The set of properties is <em>shared</em>. * * @author Jaroslav Tulach, * @version 1.00, Sep 9, 1998 */ public abstract class Node extends FeatureDescriptor { /** An empty leaf node. */ public static final Node EMPTY = new AbstractNode (Children.LEAF); /* here is list of property names that can be changed in the Node object. * These properties can be notified to the <CODE>NodeListener</CODE>. */ /** Property for node display name. */ public static final String PROP_DISPLAY_NAME = "displayName"; // NOI18N /** Property for internal (not displayable) name of a node. This name is often used to * look up a node in the hierarchy, so it should be chosen to be simple. */ public static final String PROP_NAME = "name"; // NOI18N /** Property for short description of a node. */ public static final String PROP_SHORT_DESCRIPTION = "shortDescription"; // NOI18N /** Property for the normal (closed) icon of a node. */ public static final String PROP_ICON = "icon"; // NOI18N /** Property for the opened icon of a node. */ public static final String PROP_OPENED_ICON = "openedIcon"; // NOI18N /** Property for a node's parent. */ public static final String PROP_PARENT_NODE = "parentNode"; // NOI18N /** Property for a node's list of property sets. */ public static final String PROP_PROPERTY_SETS = "propertySets"; // NOI18N /** Property for a node's cookie set. */ public static final String PROP_COOKIE = "cookie"; // NOI18N /** children representing parent node, for synchronization reasons must be changed only * under the Children.MUTEX lock */ private Children parent; /** children list, for synch. reasons change only under Children.MUTEX * lock */ Children hierarchy; /** listeners for changes in hierarchy. */ private transient EventListenerList listeners = new EventListenerList (); /** Creates a new node with a given hierarchy of children. * @exception IllegalStateException if the hierarchy is already in use by * a different node */ protected Node(Children h) throws IllegalStateException { hierarchy = h; // attaches to this node h.attachTo (this); } /** Implements {@link Object#clone} to behave correctly if cloning is desired. * But {@link Cloneable} is <em>not</em> declared by default. * <P> * The default implementation checks whether the child list implements * <code>Cloneable</code>, and if so, it clones the children. * If the child list does not support cloning, {@link Children#LEAF} is used * instead for the children. The parent of this node is set to <code>null</code> and an empty set * of listeners is attached to the node. * * @return the cloned version of the node * @exception CloneNotSupportedException if the children cannot be cloned * in spite of implementing <code>Cloneable</code> */ protected Object clone () throws CloneNotSupportedException { Node n = (Node)super.clone (); if (hierarchy instanceof Cloneable) { hierarchy = (Children)hierarchy.cloneHierarchy (); } else { hierarchy = Children.LEAF; } // attach the hierarchy hierarchy.attachTo (n); // no parent n.parent = null; // empty set of listeners n.listeners = new EventListenerList (); return n; } /** Clone the node. The newly created node should reference the same * object is this node does, but it should not be inserted as a child * to any other node. Also it should have an empty set of listeners. * In all other respects the node should behave exactly as the * original one does. * * @return copy of this node */ public abstract Node cloneNode (); /** Method that allows Children to change the parent children of * the node when the node is add to a children. * * @param parent the children that wants to contain this node * @param index index that will be assigned to this node * @exception IllegalStateException if this node already belongs to a children */ final synchronized void assignTo (Children parent, int index) { if (this.parent != null && this.parent != parent) { throw new IllegalStateException ("Cannot initialize " + index + " th node of node " + parent.getNode () + " it already belongs to node " + parent.getNode ()); // NOI18N } this.parent = parent; } /** Deassignes the node from a children, when it is removed from * a children. */ final synchronized void deassignFrom (Children parent) { if (parent != this.parent) { throw new IllegalArgumentException ("Deassign from wrong parent. Old: " + this.parent + " Caller: " + parent); //NOI18N } this.parent = null; } /** Set the system name. Fires a property change event. * @param s the new name * @exception IllegalArgumentException if the new name cannot represent * a valid node name */ public void setName (String s) { String name = super.getName (); if (name == null || !name.equals (s)) { super.setName (s); fireNameChange (name, s); } } /** Set the display name. Fires a property change event. * @param s the new name */ public void setDisplayName (String s) { String displayName = super.getDisplayName (); if (displayName == null || !displayName.equals (s)) { super.setDisplayName (s); fireDisplayNameChange (displayName, s); } } /** Set the short description of the node. Fires a property change event. * <p>This description may be used for tool tips, etc. * @param s the new description */ public void setShortDescription (String s) { String descr = super.getShortDescription (); if (descr == null || !descr.equals (s)) { super.setShortDescription (s); fireShortDescriptionChange (descr, s); } } /** Find an icon for this node (in the closed state). * @param type constant from {@link java.beans.BeanInfo} * @return icon to use to represent the node */ public abstract Image getIcon (int type); /** Find an icon for this node (in the open state). * This icon is used when the node may have children and is expanded. * * @param type constant from {@link java.beans.BeanInfo} * @return icon to use to represent the node when open */ public abstract Image getOpenedIcon (int type); /** Get context help associated with this node. * @return the context help object (could be <code>null</code> or {@link HelpCtx#DEFAULT_HELP) */ public abstract HelpCtx getHelpCtx (); /** Get the list of children. * @return the children */ public final Children getChildren () { return hierarchy; } /** Test whether the node is a leaf, or may contain children. * @return <code>true</code> if the children list is actually {@link Children#LEAF} */ public final boolean isLeaf () { return hierarchy == Children.LEAF; } /** Get the parent node. * @return the parent node, or <CODE>null</CODE> if this node is the root of a hierarchy */ public final Node getParentNode () { // if contained in a list return its parent node return parent == null ? null : parent.getNode (); } /** Test whether this node can be renamed. * If true, one can use {@link #getName} to obtain the current name and * {@link #setName} to change it. * * @return <code>true</code> if the node can be renamed */ public abstract boolean canRename (); /** Test whether this node can be deleted. * @return <CODE>true</CODE> if can */ public abstract boolean canDestroy (); // [PENDING] "valid" property? --jglick // NOI18N /** Remove the node from its parent and deletes it. * The default * implementation obtains write access to * the {@link Children#MUTEX children's lock}, and removes * the node from its parent (if any). Also fires a property change. * <P> * This may be overridden by subclasses to do any additional * cleanup. * * @exception IOException if something fails */ public void destroy () throws IOException { Children.MUTEX.postWriteRequest (new Runnable () { public void run () { if (parent != null) { // remove itself from parent parent.remove (new Node[] {Node.this} ); } // sets the valid flag to false and fires prop. change fireNodeDestroyed (); } }); } /** Get the list of property sets for this node. * E.g. typically there may be one for normal Bean properties, one for expert * properties, and one for hidden properties. * * @return the property sets */ public abstract PropertySet[] getPropertySets (); /** Called when a node is to be copied to the clipboard. * @return the transferable object representing the * content of the clipboard * @exception IOException when the * copy cannot be performed */ public abstract Transferable clipboardCopy () throws IOException; /** Called when a node is to be cut to the clipboard. * @return the transferable object representing the * content of the clipboard * @exception IOException when the * cut cannot be performed */ public abstract Transferable clipboardCut () throws IOException; /** Called when a drag is started with this node. * The node can attach a transfer listener to ExTransferable and * will be then notified about progress of the drag (accept/reject). * * @return transferable to represent this node during a drag * @exception IOException if a drag cannot be started */ public abstract Transferable drag () throws IOException; /** Test whether this node permits copying. * @return <code>true</code> if so */ public abstract boolean canCopy (); /** Test whether this node permits cutting. * @return <code>true</code> if so */ public abstract boolean canCut (); /** Determine which paste operations are allowed when a given transferable is in the clipboard. * For example, a node representing a Java package will permit classes to be pasted into it. * @param t the transferable in the clipboard * @return array of operations that are allowed */ public abstract PasteType[] getPasteTypes (Transferable t); /** Determine if there is a paste operation that can be performed * on provided transferable. Used by drag'n'drop code to check * whether the drop is possible. * * @param t the transferable * @param action the drag'n'drop action to do DnDConstants.ACTION_MOVE, ACTION_COPY, ACTION_LINK * @param index index between children the drop occured at or -1 if not specified * @return null if the transferable cannot be accepted or the paste type * to execute when the drop occures */ public abstract PasteType getDropType (Transferable t, int action, int index); /** Get the new types that can be created in this node. * For example, a node representing a Java package will permit classes to be added. * @return array of new type operations that are allowed */ public abstract NewType[] getNewTypes (); /** Get the set of actions associated with this node. * This may be used e.g. in constructing a {@link #getContextMenu context menu}. * * <P> * By default returns the actions in {@link NodeOp#getDefaultActions}. * * @return system actions appropriate to the node */ public SystemAction[] getActions () { return NodeOp.getDefaultActions (); } /** Get a special set of actions * for situations when this node is displayed as a context. * <p>For example, right-clicking on a parent node in a hierarchical view (such as * the normal Explorer) should use <code>getActions</code>. However, if this node * is serving as the parent of a (say) a window tab full of icons (e.g., in * {@link org.openide.explorer.view.IconView}), and the users right-clicks on * the empty space in this pane, then this method should be used to get * the appropriate actions for a popup menu. * <p>Note that in the Windows UI system, e.g., these action sets are quite different. * * @return actions for a context. In the default implementation, same as {@link #getActions}. */ public SystemAction[] getContextActions () { return getActions (); } /* Old, I think: --jglick * <P> * If the action should be invocable by double-click, for example in * a tree view, it must implement InvocablePresenter, that allows to obtain * an instance of Runnable and invoke the action from code. */ /** Get the default action for this node. * This action can but need not be one from the list returned * from {@link #getActions}. If so, the popup menu returned from {@link #getContextMenu} * is encouraged to highlight the action. * * @return default action, or <code>null</code> if there should be none */ public abstract SystemAction getDefaultAction (); /* misleading: --jglick * @see NodeOp#findContextMenu */ /** Make a context menu for this node. * In the default implementation, * the menu is constructed from the set of actions returned by {@link #getActions}. * * @return the popup menu */ public final JPopupMenu getContextMenu () { return NodeOp.findContextMenuImpl (new Node[] { this }); } /** Test whether there is a customizer for this node. If true, * the customizer can be obtained via {@link #getCustomizer}. * * @return <CODE>true</CODE> if there is a customizer */ public abstract boolean hasCustomizer (); /** Get the customizer component. * @return the component, or <CODE>null</CODE> if there is no customizer */ public abstract java.awt.Component getCustomizer (); /** Get a cookie for this node. * <P> * The set of cookies can change. If a node changes its set of * cookies, it fires a property change event with {@link #PROP_COOKIE}. * * @param type the representation class of the cookie * @return a cookie assignable to that class, or <code>null</code> if this node has no such cookie */ public abstract Node.Cookie getCookie (Class type); /** Obtain handle for this node (for serialization). * The handle can be serialized and {@link Handle#getNode} used after * deserialization to obtain the original node. * * @return the handle, or <code>null</code> if this node is not persistable */ public abstract Node.Handle getHandle (); /** Add a listener to changes in the node's intrinsic properties (name, cookies, etc.). * @param l the listener to add */ public final void addNodeListener (NodeListener l) { listeners.add (NodeListener.class, l); } /** Remove a node listener. * @param l the listener */ public final void removeNodeListener (NodeListener l) { listeners.remove (NodeListener.class, l); } /** Add a listener to the node's computed Bean properties. * @param l the listener */ public final void addPropertyChangeListener (PropertyChangeListener l) { listeners.add (PropertyChangeListener.class, l); } /** Remove a Bean property change listener. * @param l the listener */ public final void removePropertyChangeListener (PropertyChangeListener l) { listeners.remove (PropertyChangeListener.class, l); } /** Fire a property change event. * * @param name name of changed property (from {@link #getPropertySets}) * @param o old value * @param n new value */ protected final void firePropertyChange (String name, Object o, Object n) { // do not fire if the values are the same if (o != null && n != null && (o == n || o.equals (n))) { return; } PropertyChangeEvent ev = null; Object[] listeners = this.listeners.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == PropertyChangeListener.class) { // Lazily create the event: if (ev == null) { ev = new PropertyChangeEvent (this, name, o, n); } ((PropertyChangeListener)listeners[i+1]).propertyChange (ev); } } } /** Allow subclasses that override the getName method to fire * the changes of the name by itself. Please notice that default * implementation of setName will fire the change by itself. */ protected final void fireNameChange (String o, String n) { fireOwnPropertyChange (PROP_NAME, o, n); } /** Allow subclasses that override the getDisplayName method to fire * the changes of the name by itself. Please notice that default * implementation of setDisplayName will fire the change by itself. */ protected final void fireDisplayNameChange (String o, String n) { fireOwnPropertyChange (PROP_DISPLAY_NAME, o, n); } /** Allow subclasses that override the getShortDescription method to fire * the changes of the description by itself. Please notice that default * implementation of setShortDescription will fire the change by itself. */ protected final void fireShortDescriptionChange (String o, String n) { fireOwnPropertyChange (PROP_SHORT_DESCRIPTION, o, n); } /** Fire a change event for {@link #PROP_ICON}. */ protected final void fireIconChange () { fireOwnPropertyChange (PROP_ICON, null, null); } /** Fire a change event for {@link #PROP_OPENED_ICON}. */ protected final void fireOpenedIconChange () { fireOwnPropertyChange (PROP_OPENED_ICON, null, null); } /** Fires info about some structural change in children. Providing * type of operation and set of children changed generates event describing * the change. * * * @param addAction <CODE>true</CODE> if the set of children has been added, * false if it has been removed * @param delta the array with changed children * @param from the array of nodes to take indices from. * Can be null if one should find indices from current set of nodes */ final void fireSubNodesChange (boolean addAction, Node[] delta, Node[] from) { NodeMemberEvent ev = null; Object[] listeners = this.listeners.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == NodeListener.class) { // Lazily create the event: if (ev == null) { ev = new NodeMemberEvent (this, addAction, delta, from); } if (addAction) { ((NodeListener)listeners[i+1]).childrenAdded(ev); } else { ((NodeListener)listeners[i+1]).childrenRemoved(ev); } } } } /** Fires info about reordering of some children. * * @param indices array of integers describing the permutation */ final void fireReorderChange (int[] indices) { NodeReorderEvent ev = null; Object[] listeners = this.listeners.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == NodeListener.class) { // Lazily create the event: if (ev == null) { ev = new NodeReorderEvent (this, indices); } ((NodeListener)listeners[i+1]).childrenReordered(ev); } } } /** To all node listeners fire node destroyed notification. */ private void fireNodeDestroyed () { NodeEvent ev = null; Object[] listeners = this.listeners.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == NodeListener.class) { // Lazily create the event: if (ev == null) { ev = new NodeEvent (this); } ((NodeListener)listeners[i+1]).nodeDestroyed (ev); } } } /** Fires info about change of parent node. * @param o old node * @param n new parent */ final void fireParentNodeChange (Node o, Node n) { fireOwnPropertyChange (PROP_PARENT_NODE, o, n); } /** Fires a (Bean) property change event (for {@link #PROP_PROPERTY_SETS}). * @param o the old set * @param n the new set */ protected final void firePropertySetsChange (PropertySet[] o, PropertySet[] n) { fireOwnPropertyChange (PROP_PROPERTY_SETS, o, n); } /** Fires a change event for {@link #PROP_COOKIE}. * The old and new values are set to null. */ protected final void fireCookieChange () { fireOwnPropertyChange (PROP_COOKIE, null, null); } /** Fires info about change of own property. * @param name name of property * @param o old value * @param n new value */ final void fireOwnPropertyChange (String name, Object o, Object n) { // do not fire if the values are the same if (o != null && n != null && (o == n || o.equals (n))) { return; } PropertyChangeEvent ev = null; Object[] listeners = this.listeners.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == NodeListener.class) { // Lazily create the event: if (ev == null) { ev = new PropertyChangeEvent (this, name, o, n); } ((NodeListener)listeners[i+1]).propertyChange (ev); } } } /** Class that represents one set of properties. A usual bean has three * sets of properties: normal, expert, and events. */ public static abstract class PropertySet extends FeatureDescriptor { /** Default constructor. */ public PropertySet () { } /** Create a property set. * @param name system name of the property set * @param displayName human presentable name * @param shortDescription description for the set */ public PropertySet ( String name, String displayName, String shortDescription ) { super.setName (name); super.setDisplayName (displayName); super.setShortDescription (shortDescription); } /** Get the list of contained properties. * This list can contain both {@link Node.Property} and {@link Node.IndexedProperty} elements. * * @return the properties */ public abstract Property[] getProperties (); } /** Description of a Bean property on a node, and operations on it. */ public static abstract class Property extends FeatureDescriptor { /** type that this property works with */ private Class type; /** Constructor. * @param valueType type of the property */ public Property (Class valueType) { this.type = valueType; super.setName(""); // NOI18N } /** Get the value type. This is the representation class of the property. * Remember that e.g. {@link Boolean <code>Boolean.class</code>} means that values are <code>Boolean</code> * objects; to specify the primitive type, use e.g. {@link Boolean#TYPE}. * In the latter case, {@link #getValue} and {@link #setValue} will still operate on the wrapper object. * @return the type */ public Class getValueType () { return type; } /** Test whether the property is readable. * @return <CODE>true</CODE> if it is */ public abstract boolean canRead (); /** Get the value. * @return the value of the property * @exception IllegalAccessException cannot access the called method * @exception InvocationTargetException an exception during invocation */ public abstract Object getValue () throws IllegalAccessException, InvocationTargetException; /** Test whether the property is writable. * @return <CODE>true</CODE> if the read of the value is supported */ public abstract boolean canWrite (); /** Set the value. * @param val the new value of the property * @exception IllegalAccessException cannot access the called method * @exception IllegalArgumentException wrong argument * @exception InvocationTargetException an exception during invocation */ public abstract void setValue (Object val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; /** Test whether the property had a default value. * @return <code>true</code> if it does (<code>false</code> by default) */ public boolean supportsDefaultValue () { return false; } /** Restore this property to its default value, if supported. * In the default implementation, does nothing. * Typically you would just call e.g. <code>setValue(default)</code>. * Note that it is not permitted for this call to throw {@link IllegalArgumentException}, * though the other two exceptions from {@link #setValue} may be passed through. * @exception IllegalAccessException cannot access the called method * @exception InvocationTargetException an exception during invocation */ public void restoreDefaultValue () throws IllegalAccessException, InvocationTargetException { } /** Get a property editor for this property. * The default implementation tries to use {@link java.beans.PropertyEditorManager}. * @return the property editor, or <CODE>null</CODE> if there is no editor */ public PropertyEditor getPropertyEditor () { if (type == null) return null; return java.beans.PropertyEditorManager.findEditor(type); } /* Standart equals implementation for all property * classes. * @param property The object to compare to */ public boolean equals (Object property) { try { return ((Property)property).getName ().equals (getName ()) && ((Property)property).getValueType ().equals (getValueType ()); } catch (ClassCastException e) { return false; } } /* Returns a hash code value for the object. * * @return int hashcode */ public int hashCode () { return getName ().hashCode () * getValueType ().hashCode (); } } /** Description of an indexed property and operations on it. */ public static abstract class IndexedProperty extends Node.Property { /** type of element that this property works with */ private Class elementType; /** Constructor. * @param valueType type of the property */ public IndexedProperty (Class valueType, Class elementType) { super (valueType); this.elementType = elementType; } /** Test whether the property is readable by index. * @return <CODE>true</CODE> if so */ public abstract boolean canIndexedRead (); /** Get the element type of the property (not the type of the whole property). * @return the type */ public Class getElementType () { return elementType; } /** Get the value of the property at an index. * * @param indx the index * @return the value at that index * @exception IllegalAccessException cannot access the called method * @exception IllegalArgumentException wrong argument * @exception InvocationTargetException an exception during invocation */ public abstract Object getIndexedValue (int index) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; /** Test whether the property is writable by index. * @return <CODE>true</CODE> if so */ public abstract boolean canIndexedWrite (); /** Set the value of the property at an index. * * @param indx the index * @param val the value to set * @exception IllegalAccessException cannot access the called method * @exception IllegalArgumentException wrong argument * @exception InvocationTargetException an exception during invocation */ public abstract void setIndexedValue (int indx, Object val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; /** Get a property editor for individual elements in this property. * @return the property editor for elements */ public PropertyEditor getIndexedPropertyEditor () { return java.beans.PropertyEditorManager.findEditor (elementType); } } /** Marker interface for all cookies. * <P> * Most examples are present in {@link org.openide.cookies}. */ public static interface Cookie { } /** Serializable node reference. The node should not * be serialized directly but via this handle. One can obtain a handle * by a call to {@link Node#getHandle}. * <P> * If that methods returns a non-<code>null</code> value, one can serialize it, * and after deserialization * use {@link #getNode} to obtain the original node. */ public static interface Handle extends java.io.Serializable { static final long serialVersionUID =-4518262478987434353L; /** Reconstitute the node for this handle. * * @return the node for this handle * @exception IOException if the node cannot be created */ public Node getNode () throws java.io.IOException; } /** Obtains a resource string from bundle. * @param resName resource name * @return the string */ static String getString (final String resName) { return NbBundle.getBundle(Node.class).getString (resName); } public String toString () { return super.toString () + "[Name="+getName ()+", displayName="+getDisplayName ()+"]"; // NOI18N } } /* * Log * 29 Gandalf 1.28 1/13/00 Jesse Glick NOI18N * 28 Gandalf 1.27 1/12/00 Jesse Glick NOI18N * 27 Gandalf 1.26 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 26 Gandalf 1.25 9/16/99 Jesse Glick [JavaDoc] * 25 Gandalf 1.24 9/15/99 Jaroslav Tulach Restore default value * can throw exceptions. * 24 Gandalf 1.23 9/10/99 Jaroslav Tulach Already used bugfix. * 23 Gandalf 1.22 9/3/99 Jaroslav Tulach destroy is in * postWriteRequest * 22 Gandalf 1.21 9/2/99 Jaroslav Tulach fire(Display)NameChange * 21 Gandalf 1.20 9/1/99 Jaroslav Tulach Mutex.postWriteRequest * 20 Gandalf 1.19 8/18/99 Jaroslav Tulach writeAccess (Runnable) * instead of Mutex.Action * 19 Gandalf 1.18 8/9/99 Ian Formanek Generated Serial Version * UID * 18 Gandalf 1.17 8/2/99 Jaroslav Tulach Can be debugged better. * 17 Gandalf 1.16 7/2/99 Jesse Glick Node.drag abstract. * 16 Gandalf 1.15 6/30/99 Jaroslav Tulach Drag and drop support * 15 Gandalf 1.14 6/24/99 Jesse Glick Nodes can specify * context help (not yet retrieved by anything, though). * 14 Gandalf 1.13 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 13 Gandalf 1.12 6/8/99 Jaroslav Tulach Filter node updates * correctly when change order is performed. * 12 Gandalf 1.11 4/25/99 Ian Formanek Better toString - prints * name, displayName and handle of the Node * 11 Gandalf 1.10 4/20/99 Jaroslav Tulach Children supports weak * references. * 10 Gandalf 1.9 4/16/99 Jan Jancura Bad clone meth. * 9 Gandalf 1.8 4/12/99 Ian Formanek Removed obsoleted code * (which was already commented out, so no semantic change) * 8 Gandalf 1.7 3/29/99 David Simonek cookie action now * listens on cookie changes * 7 Gandalf 1.6 3/18/99 Jesse Glick [JavaDoc] * 6 Gandalf 1.5 3/17/99 Jesse Glick [JavaDoc] * 5 Gandalf 1.4 3/17/99 Jesse Glick [JavaDoc] * 4 Gandalf 1.3 3/17/99 Jesse Glick [JavaDoc] * 3 Gandalf 1.2 2/25/99 Jaroslav Tulach Change of clipboard * management * 2 Gandalf 1.1 2/12/99 Ian Formanek Reflected renaming * Desktop -> Workspace * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ * Beta Change History: * 0 Tuborg 0.18 --/--/98 Jan Jancura property equals, info get/setName, getElementType * 0 Tuborg 0.19 --/--/98 Jan Formanek repaired contextInvocationAction() * 0 Tuborg 0.20 --/--/98 Jaroslav Tulach removed addNodes, removeNodes, renamed getDefaultAction * 0 Tuborg 0.22 --/--/98 Jaroslav Tulach fireOwnPropertyChange only when something is changing * 0 Tuborg 0.23 --/--/98 Jan Jancura hashCode * 0 Tuborg 0.24 --/--/98 Petr Hamernik add,removeProp.listener is not final now. * 0 Tuborg 0.25 --/--/98 Jan Formanek getSubNodesCount added with default impl. * 0 Tuborg 0.26 --/--/98 Jan Jancura null type problem in the Node.Property * 0 Tuborg 0.27 --/--/98 Jan Formanek getSubNodesCount returns 0 if the Node is leaf * 0 Tuborg 0.28 --/--/98 Jan Formanek getSubNodesCount returns 0 if the Node is leaf REMOVED * 0 Tuborg 0.29 --/--/98 Jan Jancura isRoot bug. * 0 Tuborg 0.30 --/--/98 Jaroslav Tulach changed description for remove * 0 Tuborg 0.31 --/--/98 Jaroslav Tulach methods from ClipboardOperation moved to the Node * 0 Tuborg 0.33 --/--/98 Jan Formanek bugfix in equals() * 0 Tuborg 0.34 --/--/98 Jaroslav Tulach new types, popup menu generated from set of actions * 0 Tuborg 0.36 --/--/98 Jan Jancura PropertySet * 0 Tuborg 0.37 --/--/98 Jaroslav Tulach Cookie, default action * 0 Tuborg 0.38 --/--/98 Petr Hamernik Menu * 0 Tuborg 0.39 --/--/98 Jaroslav Tulach firePropertySetChange * 0 Tuborg 0.40 --/--/98 Ales Novak serialization support */